package com.todo.biz.aspect;

import com.todo.common.common.entity.response.BizPageResponse;
import com.todo.common.common.entity.response.BizResponse;
import com.todo.common.common.enums.BizEnum;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 异常捕获
 *
 * @author kaiwei
 * @date 2023-10-27 11:41:26
 */
@Slf4j
@Aspect
@Component
public class BizExceptionAspect {


    /**
     * 响应类
     */
    private static final String BIZ_RESPONSE = "com.todo.common.common.entity.response.BizResponse";

    /**
     * 分页响应
     */
    private static final String BIZ_PAGE_RESPONSE = "com.todo.common.common.entity.response.BizPageResponse";

    /**
     * 环绕
     * 处理异常的自定义处理
     *
     * @param joinPoint
     * @return
     */
    @Around("execution(* com.todo.biz.application.api.controller..*.*(..))")
    public Object aroundApiBiz(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed;
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            log.error("请求处理：{}-方法异常，异常数据：{}", signature.getMethod(), throwable.getMessage(), throwable.fillInStackTrace());
            if (throwable instanceof BizException) {
                return response(throwable, ((BizException) throwable).getErrorCode(), joinPoint.getTarget(), (MethodSignature) joinPoint.getSignature());
            }
            return response(throwable, BizErrorCodeEnum.CALL_SERVICE_ERROR, joinPoint.getTarget(), (MethodSignature) joinPoint.getSignature());
        }
        return proceed;
    }

    @Around("execution(* com.todo.biz.application.backend.controller..*.*(..))")
    public Object aroundBackendBiz(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed;
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            log.error("请求处理：{}-方法异常，异常数据：{}", signature.getMethod(), throwable.getMessage(), throwable.fillInStackTrace());
            if (throwable instanceof BizException) {
                return response(throwable, ((BizException) throwable).getErrorCode(), joinPoint.getTarget(), (MethodSignature) joinPoint.getSignature());
            }
            return response(throwable, BizErrorCodeEnum.CALL_SERVICE_ERROR, joinPoint.getTarget(), (MethodSignature) joinPoint.getSignature());
        }
        return proceed;
    }

    @Around("execution(* com.todo.biz.application.frontend.controller..*.*(..))")
    public Object aroundFrontendBiz(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed;
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            log.error("请求处理：{}-方法异常，异常数据：{}", signature.getMethod(), throwable.getMessage(), throwable.fillInStackTrace());
            if (throwable instanceof BizException) {
                return response(throwable, ((BizException) throwable).getErrorCode(), joinPoint.getTarget(), (MethodSignature) joinPoint.getSignature());
            }
            return response(throwable, BizErrorCodeEnum.CALL_SERVICE_ERROR, joinPoint.getTarget(), (MethodSignature) joinPoint.getSignature());
        }
        return proceed;
    }



    /**
     * 返回
     *
     * @param
     * @param throwable
     * @param bizEnum
     * @param target
     * @param signature
     * @return
     * @throws NoSuchMethodException
     */
    private Object response(Throwable throwable, BizEnum bizEnum, Object target, MethodSignature signature) throws NoSuchMethodException {
        String referenceClassName = getReturnReferenceClassName(target, signature);
        // 是否自定义返回message
        if (throwable instanceof BizException) {
            Object response = new BizResponse<>(bizEnum, throwable.getMessage());
            // 判断是否为控制层
            if (StringUtils.isNotBlank(referenceClassName)) {
                if (referenceClassName.startsWith(BIZ_PAGE_RESPONSE)) {
                    response = new BizPageResponse<>(bizEnum, bizEnum.getDesc() + ":" + throwable.getMessage());
                }
                if (referenceClassName.startsWith(BIZ_RESPONSE)) {
                    response = new BizResponse<>(bizEnum, bizEnum.getDesc() + ":" + throwable.getMessage());
                }
            }
            return response;
        }
        // 判断是否为控制层
        if (StringUtils.isNotBlank(referenceClassName)) {
            if (referenceClassName.startsWith(BIZ_PAGE_RESPONSE)) {
                return new BizPageResponse<>(bizEnum, bizEnum.getDesc() + ":" + throwable.getMessage());
            }
            if (referenceClassName.startsWith(BIZ_RESPONSE)) {
                return new BizResponse<>(bizEnum, bizEnum.getDesc() + ":" + throwable.getMessage());
            }
        }
        return new BizResponse<>(bizEnum, BizErrorCodeEnum.SYSTEM_ERROR.getDesc());
    }

    /**
     * 获取方法返回值的包路径
     *
     * @param target
     * @param signature
     * @return
     * @throws NoSuchMethodException
     */
    private String getReturnReferenceClassName(Object target, MethodSignature signature) throws NoSuchMethodException {
        // 获取方法
        Method method = target.getClass().getMethod(signature.getName(), signature.getParameterTypes());
        // 获取返回值类型
        return method.getAnnotatedReturnType().getType().getTypeName();
    }

}
